﻿package org.neatmvc.core {

	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	
	import org.neatmvc.utils.ClassUtil;
	import org.neatmvc.events.ControlEvent;
	
	import flash.events.Event;
	
	import org.neatmvc.core.Controller;
		
	public class View extends EventDispatcher{
	
		///////////////////////////////////////////////////////////
		//持有并维护View实例池
		//提供注册,获取,移出View实例的方法
		//管理应用中每一个INotification 的观察者(observer)列表
		//提供一个方法使IObservers绑定到 INotification的观察者列表. 
		//提供一个方法用于广播INotification. 
		//当给定的INotification被广播时,通知IObservers
		//////////////////////////////////////////////////////////////////

		private static var viewMap:Dictionary = new Dictionary();//全局视图View实例缓存池
		
		protected var viewComponent:Object;//存在于每个View子类中，储存与该View相关的特定视图组件
		
		/**
		 * This <code>IController</code> implementation is a Singleton, 
		 * so you should not call the constructor 
		 * directly, but instead call the static Singleton 
		 * Factory method <code>Controller.getInstance()</code>
		 * 
		 * @throws Error Error if Singleton instance has already been constructed
		 */
		public function View(viewComponent:Object = null) {//参数可为空？？？
		
			this.viewComponent = viewComponent;
			
			var className:String = ClassUtil.nameOf(this);
			if ( viewMap[className] != null){
				throw new Error("对象只能被实例化一次！");
			}else{
				viewMap[className] = this;
			}
			
			addEvent();
			// 执行注册时的附加操作
			this.onRegister();
		}
		
		///////////////////////////////
		//静态方法
		///////////////////////////////////////
		
		/**  
		 * 根据类名取回View
		 * @example  
		 * <listing version="3.0">  
		 * var eg:ASDocExample=new ASDocExample();  
		 * eg.print("ASDoc演示类");  
		 * eg.test("flashlizi");  
		 * </listing>  
		 * @see http://www.riaidea.com
		 */
		public static function getView(key:String):View{
			if ( viewMap[key] == null ) {
				throw new Error("对象'" + key + "' 还未实例化！");
			}else{
				return viewMap[key];
			}
		}
		
		/**  
		 * 注销View 
		 * @example  
		 * <listing version="3.0">  
		 * var eg:ASDocExample=new ASDocExample();  
		 * eg.print("ASDoc演示类");  
		 * eg.test("flashlizi");  
		 * </listing>  
		 * @see http://www.riaidea.com
		 */
		public static function removeView(key:String):View {
			var view:View= viewMap[key] as View;
			if (view) {
				viewMap[key] = null;
				delete viewMap[key];
				view.onRemove();//执行注销时的附加操作
			}
			return view;
		}
		
		/**  
		 * 视图范围内广播事件 
		 * @example  
		 * <listing version="3.0">  
		 * var eg:ASDocExample=new ASDocExample();  
		 * eg.print("ASDoc演示类");  
		 * eg.test("flashlizi");  
		 * </listing>  
		 * @see http://www.riaidea.com
		 */
		public static function notifyObsviers(e:Event):void {
			for each (var view in viewMap) { 
				if (view.hasEventListener(e.type) ){
					view.dispatchEvent(e);
				}
			}
		}
		
		/////////////////////////////
		//实例方法
		////////////////////////////////////
		
		/**
		 * 需子类覆盖：注册监听事件
		 * 设置引用强弱不会有效果，只能靠移除，因为是类级别的Function
		 * handleEvent,侦听器统一指向handleEvent，或者要单独进行Event管理来自动建立这个映射关系
		 * <listing version="3.0">
		 * </listing>
		 */ 
		public function addEvent():void {
        }
		
		/**
		 * 需子类覆盖：收到通知时需调用该方法<code>INotification</code>
		 * 处理事件，对View所侦听的事件, 即使用addEvent方法注册侦听的事件，使用switch进行处理
		 * 最佳实践: 对某些确认使用一次的事件在handleEvent中移除
		 * <listing version="3.0">
		 * 	switch ( e.type) {
		 *			case :
		 *			break;
         * 	}
		 * </listing>  
		 */ 
		public function handleEvent(e:Event):void {
        }
		
		/**
		 * 需子类覆盖：收到通知时需调用该方法<code>INotification</code>
		 * 处理事件，对View所侦听的事件, 即使用addEvent方法注册侦听的事件，使用switch进行处理
		 * 最佳实践: 对某些确认使用一次的事件在handleEvent中移除
		 * <listing version="3.0">
		 * 	switch ( e.type) {
		 *			case :
		 *			break;
         * 	}
		 * </listing>  
		 */ 
		public function sendEvent(e:Event):void {
			View.notifyObsviers(e);
			Controller.notifyObsviers(e);
		}
		
		/**
		 * 需子类覆盖：注册view时附加操作
		 * <listing version="3.0">
		 * </listing>
		 */ 
		public function onRegister( ):void {
			trace( "注册View: " + this );
		}
		
		/**
		 * 需子类覆盖：注销view时附加操作
		 * <listing version="3.0">
		 * </listing>
		 */ 
		public function onRemove( ):void {
			trace("注销View: "+this);
		}
		
	}
}